"""
Redis缓存管理模块
实现分层缓存架构（短期对话缓存+长期用户偏好存储）
支持与MySQL数据库的同步存储
"""
import redis
import json
from typing import Any, Optional
from app.core.config import settings
from sqlalchemy.orm import Session
from app.models.models import User, UserProfile, UserProgress, Conversation
from datetime import datetime

class CacheManager:
    """缓存管理器"""
    
    def __init__(self):
        """初始化Redis连接"""
        self.redis_client = redis.Redis(
            host=settings.REDIS_HOST,
            port=settings.REDIS_PORT,
            db=settings.REDIS_DB,
            decode_responses=True
        )
    
    def _get_db_session(self):
        """获取数据库会话"""
        from app.models.models import SessionLocal
        return SessionLocal()
    
    def set_short_term_cache(self, key: str, value: Any, expire: int = 3600) -> bool:
        """
        设置短期对话缓存
        
        Args:
            key: 缓存键
            value: 缓存值
            expire: 过期时间（秒），默认1小时
            
        Returns:
            是否设置成功
        """
        try:
            serialized_value = json.dumps(value, ensure_ascii=False)
            result = self.redis_client.setex(f"short_term:{key}", expire, serialized_value)
            return result
        except Exception as e:
            print(f"设置短期缓存时出错: {e}")
            return False
    
    def get_short_term_cache(self, key: str) -> Optional[Any]:
        """
        获取短期对话缓存
        
        Args:
            key: 缓存键
            
        Returns:
            缓存值，不存在则返回None
        """
        try:
            value = self.redis_client.get(f"short_term:{key}")
            if value:
                return json.loads(value)
            return None
        except Exception as e:
            print(f"获取短期缓存时出错: {e}")
            return None
    
    def set_long_term_preference(self, user_id: str, preference: Any, expire: int = 2592000) -> bool:
        """
        设置长期用户偏好存储
        同时同步到MySQL数据库
        
        Args:
            user_id: 用户ID
            preference: 用户偏好数据
            expire: 过期时间（秒），默认30天
            
        Returns:
            是否设置成功
        """
        try:
            # 更新Redis缓存
            serialized_preference = json.dumps(preference, ensure_ascii=False)
            result = self.redis_client.setex(f"user_preference:{user_id}", expire, serialized_preference)
            
            # 同步到MySQL数据库
            if result:
                db = self._get_db_session()
                try:
                    # 更新用户画像表
                    if "knowledge_level" in preference or "learning_style" in preference or "interests" in preference:
                        profile = db.query(UserProfile).filter(UserProfile.user_id == user_id).first()
                        if profile:
                            if "knowledge_level" in preference:
                                profile.knowledge_level = preference["knowledge_level"]
                            if "learning_style" in preference:
                                profile.learning_style = preference["learning_style"]
                            if "interests" in preference:
                                profile.interests = json.dumps(preference["interests"])
                            profile.updated_at = datetime.utcnow()
                        else:
                            # 创建新的用户画像记录
                            profile = UserProfile(
                                user_id=user_id,
                                knowledge_level=preference.get("knowledge_level", "beginner"),
                                learning_style=preference.get("learning_style", "visual"),
                                interests=json.dumps(preference.get("interests", []))
                            )
                            db.add(profile)
                    
                    # 更新用户进度表
                    if "progress" in preference:
                        for subject, progress_value in preference["progress"].items():
                            progress_record = db.query(UserProgress).filter(
                                UserProgress.user_id == user_id,
                                UserProgress.subject == subject
                            ).first()
                            
                            if progress_record:
                                progress_record.progress = progress_value
                                progress_record.updated_at = datetime.utcnow()
                            else:
                                progress_record = UserProgress(
                                    user_id=user_id,
                                    subject=subject,
                                    progress=progress_value
                                )
                                db.add(progress_record)
                    
                    db.commit()
                except Exception as e:
                    print(f"同步用户偏好到数据库时出错: {e}")
                    db.rollback()
                finally:
                    db.close()
            
            return result
        except Exception as e:
            print(f"设置长期偏好时出错: {e}")
            return False
    
    def get_long_term_preference(self, user_id: str) -> Optional[Any]:
        """
        获取长期用户偏好
        先从Redis获取，如果没有则从MySQL获取并更新Redis
        
        Args:
            user_id: 用户ID
            
        Returns:
            用户偏好数据，不存在则返回None
        """
        try:
            # 先从Redis获取
            preference = self.redis_client.get(f"user_preference:{user_id}")
            if preference:
                return json.loads(preference)
            
            # 如果Redis中没有，则从MySQL获取
            db = self._get_db_session()
            try:
                # 获取用户画像
                profile = db.query(UserProfile).filter(UserProfile.user_id == user_id).first()
                # 获取用户进度
                progress_records = db.query(UserProgress).filter(UserProgress.user_id == user_id).all()
                
                if profile or progress_records:
                    preference_data = {}
                    
                    if profile:
                        preference_data.update({
                            "knowledge_level": profile.knowledge_level,
                            "learning_style": profile.learning_style,
                            "interests": json.loads(profile.interests) if profile.interests else []
                        })
                    
                    if progress_records:
                        preference_data["progress"] = {
                            record.subject: float(record.progress) for record in progress_records
                        }
                    
                    # 更新Redis缓存
                    self.redis_client.setex(
                        f"user_preference:{user_id}", 
                        2592000,  # 30天
                        json.dumps(preference_data, ensure_ascii=False)
                    )
                    
                    return preference_data
            finally:
                db.close()
            
            return None
        except Exception as e:
            print(f"获取长期偏好时出错: {e}")
            return None
    
    def save_conversation_memory(self, user_id: str, memory: Any) -> bool:
        """
        保存对话记忆
        同时保存到MySQL数据库
        
        Args:
            user_id: 用户ID
            memory: 对话记忆数据
            
        Returns:
            是否保存成功
        """
        try:
            # 保存到Redis
            serialized_memory = json.dumps(memory, ensure_ascii=False)
            result = self.redis_client.set(f"conversation_memory:{user_id}", serialized_memory)
            
            # 同时保存到MySQL数据库
            if result and isinstance(memory, list):
                db = self._get_db_session()
                try:
                    # 保存最近的几条对话记录到数据库
                    for conversation in memory[-10:]:  # 只保存最近10条
                        if isinstance(conversation, dict) and "question" in conversation and "answer" in conversation:
                            conv_record = Conversation(
                                user_id=user_id,
                                question=conversation["question"],
                                answer=conversation["answer"],
                                sources=json.dumps(conversation.get("sources", []))
                            )
                            db.add(conv_record)
                    
                    db.commit()
                except Exception as e:
                    print(f"保存对话记录到数据库时出错: {e}")
                    db.rollback()
                finally:
                    db.close()
            
            return result
        except Exception as e:
            print(f"保存对话记忆时出错: {e}")
            return False
    
    def load_conversation_memory(self, user_id: str) -> Optional[Any]:
        """
        加载对话记忆
        先从Redis获取，如果没有则从MySQL获取并更新Redis
        
        Args:
            user_id: 用户ID
            
        Returns:
            对话记忆数据，不存在则返回None
        """
        try:
            # 先从Redis获取
            memory = self.redis_client.get(f"conversation_memory:{user_id}")
            if memory:
                return json.loads(memory)
            
            # 如果Redis中没有，则从MySQL获取
            db = self._get_db_session()
            try:
                # 获取最近的对话记录
                conversations = db.query(Conversation)\
                    .filter(Conversation.user_id == user_id)\
                    .order_by(Conversation.created_at.desc())\
                    .limit(10)\
                    .all()
                
                if conversations:
                    # 按时间顺序排列（从旧到新）
                    conversations.reverse()
                    memory_data = [
                        {
                            "question": conv.question,
                            "answer": conv.answer,
                            "sources": json.loads(conv.sources) if conv.sources else [],
                            "created_at": conv.created_at.isoformat()
                        }
                        for conv in conversations
                    ]
                    
                    # 更新Redis缓存
                    self.redis_client.set(
                        f"conversation_memory:{user_id}",
                        json.dumps(memory_data, ensure_ascii=False)
                    )
                    
                    return memory_data
            finally:
                db.close()
            
            return None
        except Exception as e:
            print(f"加载对话记忆时出错: {e}")
            return None

# 全局缓存管理器实例
cache_manager = CacheManager()